package com.zrz.util;


/**
 * 唯一id生成工具类
 *

 */
public final class UniqueIdGenerateUtils {

    /**id工作对象*/
    private static IdWorker idWorker;


    /**
     * 隐藏构造器
     */
    private UniqueIdGenerateUtils() {
    }


    /**
     * 保证同一毫秒生成的id是自增的
     * @author
     * @since 2016/9/7 10:03
     * @return 生成的唯一id
     */
    public  static long generateNextId() {
        if (idWorker == null) {
            idWorker = new IdWorker(1, 1);
        }
        return idWorker.nextId();
    }





    /**
     * IdWorker 类
     *
     * @author
     * @since 2016/6/5  14:54
     */
    public static class IdWorker {

        /**工作id*/
        private long workerId;
        /**数据中心id*/
        private long datacenterId;
        /**序列*/
        private long sequence = 0L;
        /**时间戳基础*/
        private long twepoch = 1288834974657L; // SUPPRESS CHECKSTYLE
        /**工作id 比特位*/
        private long workerIdBits = 5L; // SUPPRESS CHECKSTYLE
        /**数据中心比特位*/
        private long datacenterIdBits = 5L; // SUPPRESS CHECKSTYLE
        /**最大工作id*/
        private long maxWorkerId = -1L ^ (-1L << workerIdBits); // SUPPRESS CHECKSTYLE
        /**最大数据中心id*/
        private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // SUPPRESS CHECKSTYLE
        /**序列长度*/
        private long sequenceBits = 12L; //序列长度默认12 SUPPRESS CHECKSTYLE
        /**workerIdShift*/
        private long workerIdShift = sequenceBits;
        /**datacenterIdShift*/
        private long datacenterIdShift = sequenceBits + workerIdBits;
        /**timestampLeftShift*/
        private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
        /**sequenceMask*/
        private long sequenceMask = -1L ^ (-1L << sequenceBits); // SUPPRESS CHECKSTYLE
        /**最后的时间戳*/
        private long lastTimestamp = -1L;

        /**
         * 构造函数
         * @author
         * @since  2016/9/7 10:18
         * @param  workerId workerId
         * @param  datacenterId datacenterId
         */
        public IdWorker(long workerId, long datacenterId) {
            if (workerId > maxWorkerId || workerId < 0) {
                throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            if (datacenterId > maxDatacenterId || datacenterId < 0) {
                throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
            }
            this.workerId = workerId;
            this.datacenterId = datacenterId;
//            LogUtils.debug(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
//                    timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
        }

        /**
         *  获取下一个id
         * @author
         * @since  2016/9/7 10:18
         * @return   下一个id
         */
        public synchronized long nextId() {
            long timestamp = timeGen();
//            LogUtils.debug("time:" + timestamp);
            if (timestamp < lastTimestamp) {
                LogUtils.debug(String.format("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp));
                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
            }
            if (lastTimestamp == timestamp) {
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0L;
            }
            lastTimestamp = timestamp;
            return (((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence) + Thread.currentThread().getId();
        }

        /**
         * 下一毫秒
         * @param lastTimestamp  lastTimestamp
         * @author
         * @since  2016/9/7 10:18
         * @return 下一毫秒
         */
        protected long tilNextMillis(long lastTimestamp) {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp) {
                timestamp = timeGen();
            }
            return timestamp;
        }

        /**
         * 生成时间
         * @author
         * @since  2016/9/7 10:18
         * @return 下一毫秒
         */
        protected long timeGen() {
            return System.currentTimeMillis();
        }
    }


}
